#ifndef AFCORE_DATABASE_DATABASE_DATABASE_FIELD_
#define AFCORE_DATABASE_DATABASE_DATABASE_FIELD_

#include <vector>

#include "define.h"
#include "database_fwd.h"

namespace afcore {

/// @brief  数据库
namespace database {

/// @brief  数据库字段类型
enum class EDatabaseFieldType : uint8_t {
  kDatabaseFieldType_Null,      ///< 空
  kDatabaseFieldType_Int8,      ///< 8位
  kDatabaseFieldType_Int16,     ///< 16位
  kDatabaseFieldType_Int32,     ///< 32位
  kDatabaseFieldType_Int64,     ///< 64位
  kDatabaseFieldType_Float,     ///< 浮点
  kDatabaseFieldType_Double,    ///< 双精度浮点
  kDatabaseFieldType_Decimal,   ///< 小数
  kDatabaseFieldType_Date,      ///< 日期
  kDatabaseFieldType_Binary     ///< 二进制
};

/// @brief  用于访问数据库查询的各类字段
/// 下表是访问mysql类型对应的方法
///  |   MySQL type           |  method to use                         |
///  |------------------------|----------------------------------------|
///  | TINYINT                | GetBool, GetInt8, GetUInt8             |
///  | SMALLINT               | GetInt16, GetUInt16                    |
///  | MEDIUMINT, INT         | GetInt32, GetUInt32                    |
///  | BIGINT                 | GetInt64, GetUInt64                    |
///  | FLOAT                  | GetFloat                               |
///  | DOUBLE, DECIMAL        | GetDouble                              |
///  | CHAR, VARCHAR,         | GetCString, GetString                  |
///  | TINYTEXT, MEDIUMTEXT,  | GetCString, GetString                  |
///  | TEXT, LONGTEXT         | GetCString, GetString                  |
///  | TINYBLOB, MEDIUMBLOB,  | GetBinary, GetString                   |
///  | BLOB, LONGBLOB         | GetBinary, GetString                   |
///  | BINARY, VARBINARY      | GetBinary                              |
class AFCORE_DATABASE_API CField {
  friend class CResultSet;
  friend class CPreparedResultSet;
public:
  /// @brief  构造函数
  CField();
  /// @brief  析构函数
  ~CField();

  /// @brief  获取bool类型值
  /// @return bool类型值
  bool GetBool() const;
  /// @brief  获取uint8类型值
  /// @return uint8类型值
  uint8_t GetUInt8() const;
  /// @brief  获取int8类型值
  /// @return int8类型值
  int8_t GetInt8() const;
  /// @brief  获取uin16类型值
  /// @return uin16类型值
  uint16_t GetUInt16() const;
  /// @brief  获取int16类型值
  /// @return int16类型值
  int16_t GetInt16() const;
  /// @brief  获取uint32类型值
  /// @return uint32类型值
  uint32_t GetUInt32() const;
  /// @brief  获取int32类型值
  /// @return int32类型值
  int32_t GetInt32() const;
  /// @brief  获取uint64类型值
  /// @return uint64类型值
  uint64_t GetUInt64() const;
  /// @brief  获取int64类型值
  /// @return int64类型值
  int64_t GetInt64() const;
  /// @brief  获取float类型值
  /// @return float类型值
  float GetFloat() const;
  /// @brief  获取double类型值
  /// @return double类型值
  double GetDouble() const;
  /// @brief  获取c风格字符串类型值
  /// @return c风格字符串类型值
  char const* GetCString() const;
  /// @brief  获取string类型值
  /// @return string类型值
  std::string GetString() const;
  /// @brief  获取二进制字节流类型值
  /// @return 二进制字节流类型值
  std::vector<uint8_t> GetBinary() const;
  /// @brief  判断数据是否为空
  /// @return true    数据为空
  /// @return false   数据不为空
  bool IsNull() const;

  /// @brief  原始类型数据
  struct SMetadata {
    const char* table_name;   ///< 表组织名称
    const char* table_alias;  ///< 列表
    const char* name;         ///< 原始列名
    const char* alias;        ///< 列名
    const char* type;         ///< 数据类型
    uint32_t index;           ///< 字段索引
  };
protected:
  /// @brief  字段数据结构
  struct alignas(1) SData {
    uint32_t length {0}; ///< 数据长度
    void* value {nullptr}; ///< 数据值
    EDatabaseFieldType type {EDatabaseFieldType::kDatabaseFieldType_Null}; ///< 数据类型
    bool raw {false}; ///< true 内置数据 false 结构体数据
  } data_;

  /// @brief  设置内置数据类型
  /// @param  new_value       新的类型值 泛型
  /// @param  new_type        新的字段数据类型
  /// @param  length          数据长度
  void SetByteValue(void* new_value, EDatabaseFieldType new_type, uint32_t length);
  /// @brief  设置结构数据类型
  /// @param  new_value       新的类型值 泛型
  /// @param  new_type        新的字段数据类型
  /// @param  length          数据长度
  void SetStructuredValue(char* new_value, EDatabaseFieldType new_type, uint32_t length);

  /// @brief  数据清理
  void CleanUp();

  /// @brief  检查当前字段是否是传入的类型
  /// @param  要检查的类型
  /// @return true            类型一致
  /// @return false           类型不一致
  bool IsType(EDatabaseFieldType type) const;

  /// @brief  检查当前字段是否为数字
  /// @return true            是数字
  /// @return false           非数字
  bool IsNumeric() const;
private:
#if defined(AFCORE_DEBUG)
  /// @brief  错误日志
  /// @param  getter          获取类型的函数名
  void LogWrongType(const char* getter) const;
  /// @brief  设置原始数据类型
  /// @param  field           字段数据
  /// @param  field_index     字段索引
  void SetMetadata(SMysqlField* field, uint32_t field_index);
#endif
private:
#if defined(AFCORE_DEBUG)
  SMetadata meta_; ///< 原始数据 调试用
#endif
};

} // !namespace database

} // !namespace afcore


#endif //! AFCORE_DATABASE_DATABASE_DATABASE_FIELD_